﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Collections.Generic;
using System.Threading;
using System.Web;
using Microsoft.SharePoint;

namespace AWS.SLAM.Configuration
{
    /// <summary>
    /// The SlamItemContext provides access to the SPListItem currently being processed by SLAM anywhere within SLAM's processing stack.
    /// </summary>
    public static class SlamItemContext
    {
        private static List<string> _contextFields = new List<string>();
        /// <summary>
        /// The SPListItem currently being processed by SLAM.
        /// </summary>
        public static SPListItem ListItem
        {
            get 
            {
                SPListItem currentListItem = null;
                object propertyValue = GetPropertyValue("CurrentSLAMListItem");
                if (propertyValue != null)
                {
                    currentListItem = (SPListItem)propertyValue;
                }
                return currentListItem;
            }
            set
            {
                SetPropertyValue("CurrentSLAMListItem", value);
            }
        }
        
        /// <summary>
        /// Indiciates whether the SPListItem currently being processed by SLAM is configured
        /// to be slammed based on its Content Type or parent List.
        /// </summary>
        public static bool ProcessedByContentType 
        {
            get 
            {   
                bool currentListItemProcessedByContentType = false;
                object propertyValue = GetPropertyValue("CurrentSLAMListItemProcessedByContentType");
                if (propertyValue != null)
                {
                    currentListItemProcessedByContentType = (bool)propertyValue;
                }
                return currentListItemProcessedByContentType;
            }
            set
            {
                SetPropertyValue("CurrentSLAMListItemProcessedByContentType", value);
            }
        }

        /// <summary>
        /// Name of the List or Content Type configured to be managed by SLAM that corresponds with the SPListItem 
        /// currently being processed.  In the case of Lists this is the SPListItem's parent List Title, in the case
        /// of Content Types this is the SPListItem's Content Type Name or the Name of a parent Content Type.
        /// </summary>
        public static string TypeName
        {
            get
            {
                string currentTypeName = "";
                object propertyValue = GetPropertyValue("CurrentSLAMListItemTypeName");
                if (propertyValue != null)
                {
                    currentTypeName = (string)propertyValue;
                }
                return currentTypeName;
            }
            set
            {
                SetPropertyValue("CurrentSLAMListItemTypeName", value);
            }
        }

        /// <summary>
        /// Resets the SLAM Item Context by clearing its properties
        /// </summary>
        public static void ResetContext()
        {
            foreach (string field in _contextFields)
            {
                //Check if HttpContext is available, if it is, clear the stored item from HttpContext Items
                if (HttpContext.Current != null)
                {
                    if (HttpContext.Current.Items.Contains(field))
                    {
                        HttpContext.Current.Items.Remove(field);
                    }
                }
                else
                {
                    //If the HttpContext is not available, clear the stored item from the Thread's local data store
                    Thread.FreeNamedDataSlot(field);
                }
            }
        }

        private static object GetPropertyValue(string propertyName)
        {
            object property = null;

            //Check if HttpContext is available, if it is, this property
            //should be stored in HttpContext Items
            if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items.Contains(propertyName))
                {
                    property = HttpContext.Current.Items[propertyName];
                }
            }
            else
            {
                //If the HttpContext is not available, the context is needed within an 
                //asynchronous event in which case the context data should be stored
                //in the Thread's local data store
                LocalDataStoreSlot storeSlot = Thread.GetNamedDataSlot(propertyName);
                if (storeSlot != null)
                {
                    property = Thread.GetData(storeSlot);
                }
            }
            return property;
        }

        private static void SetPropertyValue(string propertyName, object value)
        {
            //Check if HttpContext is available, if it is, store the property for this SLAM item context
            //in HttpContext Items
            if (HttpContext.Current != null)
            {
                if (!HttpContext.Current.Items.Contains(propertyName))
                {
                    HttpContext.Current.Items.Add(propertyName, value);
                }
                else
                {
                    HttpContext.Current.Items[propertyName] = value;
                }
            }
            else
            {
                //If the HttpContext is not available, the context is needed within an 
                //asynchronous event in which case the context data can be stored
                //in the Thread's local data store
                Thread.SetData(Thread.GetNamedDataSlot(propertyName), value);
            }

            if (!_contextFields.Contains(propertyName))
            {
                _contextFields.Add(propertyName);
            }
        }
    }
}
